package com.picturehistory.core.jersey.resources;

import java.util.List;

import javax.management.openmbean.InvalidKeyException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import com.picturehistory.core.jersey.exception.InvalidArgException;
import com.picturehistory.core.jersey.exception.InvalidPinException;
import com.picturehistory.core.jersey.exception.InvalidUserException;
import com.picturehistory.core.jersey.model.Article;
import com.picturehistory.core.jersey.services.ArticleService;
import com.picturehistory.core.jersey.util.Response;

@Path("/article")
@Component 
public class ArticleResource {
	final Logger logger = LoggerFactory.getLogger(ArticleResource.class);
	
	@Autowired
	private ArticleService service;
	
	
	@GET
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Article getArticle(
			@Context               UriInfo uri,
			@HeaderParam("userId") String  user,
			@HeaderParam("key")    String  key
	) {
		logger.info("[REQ GET /article] with uri = " + uri.getPath());
		
		if (user == null) {
			// How do I change returning header value?
			// I want to alert the client that the exception has occurred
			// and there is nothing to display...
			return null;
		}
		else if (key == null) {
			return null;
		}
		
		logger.info("user=" + user + ", key=" + key);
		
		long id = -1;
		try {
			id = Long.parseLong(key);
		} catch(Exception e) {
			logger.info("provided key cannot be converted to long value");
			return null;
		}
		
		Article ret = service.getArticleById(id);
		return ret;
	}
	
	@POST
	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Response postArticle(
			@Context UriInfo uri, 
			@HeaderParam("userId") String user,
			@HeaderParam("pin") String pin,
			Article at
	) {
		logger.info("[REQ POST /article] with uri = " + uri.getPath());
		
		Response ret = new Response();
		if (at == null) {
			logger.debug("Article is null");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided Article value is null");
		}
		else if (user == null) {
			logger.debug("User is null");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided User value is null");
		}
		else if (pin == null) {
			logger.debug("PIN is null");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided PIN value is null");
		}
		else if (at.getAuthor() == null || !at.getAuthor().equals(user)) {
			logger.debug("Provided User information is different from Author in Article");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided User information is different from Author in Article");
		} 
		else {
			try {
				logger.info("Store an article");
				service.storeArticle(user, pin, at);
				
				ret.setResult(Response.OK);
				ret.setMessage("Successfully stored an article");
			} 
			catch (InvalidUserException e) {
				ret.setResult(Response.FAILED);
				ret.setMessage("User information is invalid: " + e.getMessage());
			} 
			catch (InvalidPinException e) {
				ret.setResult(Response.FAILED);
				ret.setMessage("PIN is invalid: " + e.getMessage());
			}
		}
		
		return ret;
	}
	
	@PUT
	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Response updateArticle(
			@Context UriInfo uri,
			@HeaderParam("userId") String user,
			@HeaderParam("key") String key,
			@HeaderParam("pin") String pin,
			Article at
	) {
		logger.info("[REQ PUT /article] with uri = " + uri.getPath());
		
		Response ret = new Response();
		if (at == null) {
			logger.debug("Article is null");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided Article value is null");
		}
		else if (key == null) {
			logger.debug("Key is null");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided Key value is null");
		}
		else if (user == null) {
			logger.debug("User is null");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided User value is null");
		}
		else if (pin == null) {
			logger.debug("PIN is null");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided PIN value is null");
		}
		else if (!at.getAuthor().equals(user)) {
			logger.debug("Provided User information is different from Author in Article");
			ret.setResult(Response.FAILED);
			ret.setMessage("provided User information is different from Author in Article");
		} 
		else {
			try {
				logger.info("Update an article");
				
				Article result = service.updateArticle(user, Long.parseLong(key), pin, at);
				
				//result not being used for now
				
				ret.setResult(Response.OK);
				ret.setMessage("Successfully updated an article");
			} 
			catch (NumberFormatException r) {
				ret.setResult(Response.FAILED);
				ret.setMessage("provided key cannot be convered to long value");
			}
			catch (InvalidUserException e) {
				ret.setResult(Response.FAILED);
				ret.setMessage("User information is invalid: " + e.getMessage());
			} 
			catch (InvalidPinException e) {
				ret.setResult(Response.FAILED);
				ret.setMessage("PIN is invalid: " + e.getMessage());
			}
			catch (InvalidKeyException e) {
				ret.setResult(Response.FAILED);
				ret.setMessage("key is invalid: " + e.getMessage());
			}
		}
		
		return ret;
	}
	
	@DELETE
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Response deleteArticle(
			@Context UriInfo uri,
			@HeaderParam("user") String user,
			@HeaderParam("key") String key,
			@HeaderParam("pin") String userPin
	) {
		logger.info("[REQ DELETE /article] with uri = " + uri.getPath());
		
		return null;
	}
	
	@GET
	@Path("/search")
	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public List<Article> getArticlesNear(
			@Context UriInfo uri
	) {
		logger.info("[REQ GET /article/{x}/{y}] with uri = " + uri.getPath());
		List<Article> ret = service.loadArticleByXY(100, 100);
		
		return ret;
	}
	
	@GET
	@Path("/search")
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public List<Article> getArticlesNearParams(
			@Context UriInfo uri,
			@QueryParam("q") String type,
			@QueryParam("geopoint") @DefaultValue("0,0,0") String geo
			
	) {
		logger.info("[REQ GET /article/{x}/{y}] with uri = " + uri.getPath());
		List<Article> ret = service.loadArticleByXY(100, 100);
		
		return ret;
	}
	
	/* Test purpose only */
	@GET
	@Path("/test")
	@Produces("text/plain")
	public String connectionTest() {
		return "good";
	}
	
	@POST
	@Path("/{x}/{y}/{title}")
	@Consumes("text/plain")
	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
	public Article postArticleManually(
			@Context UriInfo uri,
			@PathParam("x") Integer x,
			@PathParam("y") Integer y,
			@PathParam("title") String title,
			String body
			/*, @QueryParam("tag") @DefaultValue("") String tag */
	) {
		Article at = new Article(x, y, "admin", title, null, body);
		service.storeArticle("", "", at);
		return at;
	}
	
	
}
